package dan.common

import chisel3._
import chisel3.util._
import dan.common.Consts._
import os.group.set
import dan.frontend._
import dan.backend.DcacheReq

class ICacheParam(fetchWidth: Int){
    // TODO
    val vaBits: Int = 32
    val setNum: Int = 64
    val wayNum: Int = 8
    val bytesPerLine: Int = 64
    val idx4SetBits: Int = log2Ceil(setNum)
    val idxInLineBits: Int = log2Ceil(bytesPerLine)
    val tagBits: Int = vaBits - idx4SetBits - idxInLineBits
    val noTagBits: Int = vaBits - tagBits
    val fetchBytes: Int = fetchWidth * 4
    val fetchPackPerLine: Int = bytesPerLine / fetchBytes       // 每个cache line取多少次指令
    require(isPow2(fetchPackPerLine))
}

class FrontendParam{
    //TODO
    val instrBytes: Int = 4
    val fetchWidth: Int = 4
    val fetchBytes: Int = fetchWidth * instrBytes
    val ftqSize: Int = 16
    val fetchBufSize: Int = 9
    val iCacheParam: ICacheParam = new ICacheParam(fetchWidth)
    // TODO HasBPUParam trait
    val bpu = new HasBPUParam {}
    val targetBits = bpu.targetBits
    val rasSize = bpu.rasSize
    def getTargetPC(pc: UInt, target: UInt): UInt = bpu.getTargetPC(pc, target) 
    def getTarget(targetPC: UInt): UInt = bpu.getTarget(targetPC)
}

class ROBParam(coreWidth: Int){
    //TODO
    val robSize: Int = 36
    val retireWidth: Int = coreWidth
    val robRowNum: Int = robSize / retireWidth
    val robIdxBits: Int = log2Ceil(robSize)
}

class LSUParam{
    //TODO
    // 分成两条队列，load queue和store queue
    val ldqSize: Int = 12
    val ldqIdxBits: Int = log2Ceil(ldqSize)
    val stqSize: Int = 12
    val stqIdxBits: Int = log2Ceil(stqSize)
}

class DcacheParam{
    //TODO
    val vaBits: Int = 32
    val wordsPerLine: Int = 16
    def bytesPerLine: Int = wordsPerLine * 4
    def bitsPerLine: Int = bytesPerLine * 8
    val setNum: Int = 64
    val wayNum: Int = 4
    def wordsTotal = setNum * wayNum * wordsPerLine
    def idxFlatWordBits = log2Ceil(wordsTotal)
    /* 
        含义: MSHR (Miss Status Handling Register) 的数量。
        解释: MSHR 是一个非常关键的组件，用于处理缓存未命中。当发生 cache miss 时，
        需要向下一级存储（如 L2 Cache 或主存）发送请求。MSHR 会记录下这次 miss 的
        所有信息（如请求的地址、是读还是写等），并允许多个对同一缓存块的请求合并处理。
        这使得缓存在处理一次 miss 的漫长等待期间，仍然可以继续接收和处理其他不相关的请求，
        实现了非阻塞缓存。
    
     */
    val TLBENum: Int = 32   // maybe unused
    val MSHRNum: Int = 8    // maybe unused
    val memWidth = 2
    val l0MSHRNum = 2
    val l1MSHRNum = 3
    def idxInLineBits: Int = log2Ceil(bytesPerLine)
    def idx4SetBits: Int = log2Ceil(setNum)
    def tagBits = vaBits - idx4SetBits - idxInLineBits
    def ageBits = 10        // for lru
    val coreDataBits: Int = 32  // core数据位宽，maybe unused
    val blockBits: Int = vaBits - idxInLineBits     // 融合一个line内所有word的cache“切片”为一个block

    def getTagAddr(va: UInt): UInt = va(vaBits-1, idxInLineBits + idx4SetBits)
    def getWordAddr(va: UInt): UInt = va(idxInLineBits-1, 2)
    def getSetAddr(va: UInt): UInt = va(idxInLineBits + idx4SetBits + 1, idxInLineBits)
    def getBlockAddr(va: UInt): UInt = va(vaBits-1, idxInLineBits)
    def isLL(req: DcacheReq): Bool = req.uop.isLL
    def isSC(req: DcacheReq): Bool = req.uop.isSC
    def isStore(req: DcacheReq): Bool = req.uop.useStQ
    def isMMIO(req: DcacheReq): Bool = req.uncacheable
    def isUncacheable(req: DcacheReq): Bool = req.uncacheable
}

case class IssueParam(
    iqType: Int,
    iqSlotsNum: Int,
    dispatchWidth: Int,
    issueWidth: Int
)

trait HasCoreParam {
    // TODO
    val resetPC:Int = 0x1C000000
    val xBits: Int = 32
    val vaBits: Int = xBits
    val paBits: Int = xBits
    val instrBytes: Int = 4
    val instrBits: Int = instrBytes * 8
    val coreWidth: Int = 3
    val memWidth: Int = 2
    val maxBrNum: Int = 8
    val brTagBits: Int = log2Ceil(maxBrNum)
    val archRegNum: Int = 32
    val archRegBits: Int = log2Ceil(archRegNum)
    val physRegNum: Int = 63
    val physRegBits: Int = log2Ceil(physRegNum)
    val frontendParam: FrontendParam = new FrontendParam()
    val robParam: ROBParam = new ROBParam(coreWidth)
    val lsuParam: LSUParam = new LSUParam
    val dcacheParam: DcacheParam = new DcacheParam
    val issueParams: Seq[IssueParam] = Seq(
        IssueParam(iqType = IQT_MEM.litValue.toInt, iqSlotsNum = 6, dispatchWidth = 3, issueWidth = 2),
        IssueParam(iqType = IQT_INT.litValue.toInt, iqSlotsNum = 10, dispatchWidth = 3, issueWidth = 3),
    )
}

abstract class CoreModule extends Module with HasCoreParam
abstract class CoreBundle extends Bundle with HasCoreParam

